local gamelib = require "club.threecard.gamelib"
local app = require "app"
local Sprite = CS.UnityEngine.Sprite
local RuntimeAnimatorController = CS.UnityEngine.RuntimeAnimatorController
local Vector2 = CS.UnityEngine.Vector2
local Vector4 = CS.UnityEngine.Vector4
local Material = CS.UnityEngine.Material
local type_material = typeof(Material);
local RectTransform = CS.UnityEngine.RectTransform
local Edge = RectTransform.Edge

local anchor_middle = Vector2(0.5, 0.5)
local zero_pos = Vector2.zero

local element = gamelib.ui.element();

local log = gamelib.logging.get("slot element")

local default_config = 
{
    res = "club.threecard.slotlib/ui/common.b:element_temp",
    img = "club.threecard.slotlib/atlases/common.b:1:"..typeof(Sprite).AssemblyQualifiedName,
    animator = "club.threecard.slotlib/ui/common.b:element:"..typeof(RuntimeAnimatorController).AssemblyQualifiedName,
}

local motion_material = nil;

local function get_motion_material(sprite)
    if motion_material then
        return motion_material;
    end

    local opt = {sync = true};
    local isOk, mat = app.res.load(string.format("club.threecard.slotlib/ui/common.b:%s:%s", "motion_symbol", type_material.AssemblyQualifiedName), opt);
    if isOk then
        motion_material = mat;
    end


    local unit_y = 1/sprite.texture.width;
    motion_material:SetFloat("_Unit_y", unit_y);
    return motion_material;
end

local valid_mat = {};
local invalid_mat = {};
local mat_temp = nil;
local function get_material()
    if #valid_mat > 0 then
        local ret = valid_mat[#valid_mat];
        table.remove(valid_mat)
        invalid_mat[ret] = true;
        return ret;
    end

    if mat_temp == nil then
        local opt = {sync = true};
        local isOk, mat = app.res.load(string.format("club.threecard.slotlib/ui/common.b:%s:%s", "symbol_outline", type_material.AssemblyQualifiedName), opt);
        if isOk then
            mat_temp = mat;
        end
    end

    if mat_temp == nil then
        return;
    end

    local ret = Material(mat_temp);
    invalid_mat[ret] = true;
     return ret;
end

local function put_material(mat)
    if not invalid_mat[mat] then
        return;
    end

    table.insert(valid_mat, mat);
    invalid_mat[mat] = nil;
end

function element:ctor(config, index, width, height)
    self.index = index;
    self.config = config;
    self.width = width or 100;
    self.height = height or 100;

    self.res = config.res or default_config.res;
    self.img_uri = config.img or default_config.img;
    self.animator_uri = config.animator or default_config.animator;
end

local function check_native_size(self)
    if not self.img then
        return;
    end

    self.img_rect = self.img.transform:GetComponent(typeof(RectTransform));

    if self.config.native_size then
        self.img_rect.anchorMin = anchor_middle;
        self.img_rect.anchorMax = anchor_middle;
        self.img_rect.anchoredPosition = zero_pos;
        self.img:SetNativeSize(true);
    else
        self.img_rect.anchorMin = Vector2.zero;
        self.img_rect.anchorMax = Vector2.one;
        self.img_rect.sizeDelta = Vector2.zero;
    end
end

function element:on_load()
    self:super("on_load");
    self.rect.sizeDelta = Vector2(self.width, self.height);

    if self.img_uri then
        local ok, result = self.app.res.load(self.img_uri);
        if ok then
            self.img.sprite = result;
            self.img.material = nil;
            check_native_size(self);
        else
            error(result)
        end
    end

    if self.animator_uri then
        local ok, result = self.app.res.load(self.animator_uri);
        if ok then
            self.animator.runtimeAnimatorController = result;
        else
            error(result)
        end
    end
end

function element:change_config(config)
    if self.config ~= config then
        self.should_change_view = true;
        self.config = config;
        if self.config == nil then
            log.error("nil xxx");
        end
    end
end

-- 屏幕外
function element:on_over_view()
    if self.should_change_view then
        self.img_uri = self.config.img or default_config.img;
        self.animator_uri = self.config.animator or default_config.animator;
        gamelib.coroutine.start(function()
            if self.img_uri then
                local ok, result = self.app.res.load(self.img_uri);
                if ok then
                    self.img.sprite = result;
                    check_native_size(self);
                else
                    error(result)
                end
            end
        
            if self.animator_uri then
                local ok, result = self.app.res.load(self.animator_uri);
                if ok then
                    self.animator.runtimeAnimatorController = result;
                else
                    error(result)
                end
            end
        end)
        self.should_change_view = false;
    end
end

function element:on_view_port()
    if not self.img then
        return;
    end

    self.img.material = get_motion_material(self.img.sprite);
end

function element:on_stop()
    if not self.img then
        return;
    end

    self.img.material = nil;
end

function element:perform()
    self.animator:Play("element_performance", 0, 0);
    if self.outline then
        self.outline.material = get_material();
    end
end

-- 只是提供默认的一种动画方式，如果不一样继承重写就好了
function element:active(b)
    if b then
        self.animator:Play("element_active", 0, 0);
    else
        if self.outline then
            put_material(self.outline.material);
        end
        self.animator:Play("element_deactive", 0, 0);
    end
end

function element:on_injected(bind)
    self.rect_transform = self.gameobject:GetComponent(typeof(CS.UnityEngine.RectTransform))
end

return element